package topcbl.net;

import java.io.IOException;
import java.util.Timer;
import java.util.TimerTask;

import org.apache.http.HttpResponse;
import org.apache.http.client.HttpClient;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.impl.client.DefaultHttpClient;
import org.jivesoftware.smack.AccountManager;
import org.jivesoftware.smack.ConnectionConfiguration;
import org.jivesoftware.smack.XMPPConnection;
import org.jivesoftware.smack.XMPPException;
import org.jivesoftware.smack.packet.Presence;
import org.json.JSONArray;
import org.json.JSONException;
import org.json.JSONObject;

import topcbl.data.CarState;
import topcbl.task.GetCarInfoTask;
import topcbl.task.GetNearCarTask;
import topcbl.taxi.R;
import topcbl.taxi.WaitTaxiActivity;
import topcbl.util.StringUtils;
import android.app.Service;
import android.content.Context;
import android.content.Intent;
import android.graphics.Bitmap;
import android.graphics.PixelFormat;
import android.graphics.drawable.AnimationDrawable;
import android.graphics.drawable.BitmapDrawable;
import android.os.Binder;
import android.os.Handler;
import android.os.IBinder;
import android.util.Log;
import android.view.Gravity;
import android.view.LayoutInflater;
import android.view.MotionEvent;
import android.view.View;
import android.view.WindowManager;
import android.widget.ImageView;
import android.widget.RelativeLayout;

import com.google.android.gms.maps.model.LatLng;

public class TaxiService extends Service {
	private final IBinder mBinder = new TaxiBinder();
	// connection with server
	private XMPPConnection mConnection;
	private boolean isConnected = false;
	private boolean isLogin = false;

	public class TaxiBinder extends Binder {
		public TaxiService getService() {
			return TaxiService.this;
		}
	}

	@Override
	public void onCreate() {
		super.onCreate();
		connectServerXMPP();
	}

	@Override
	public int onStartCommand(Intent intent, int flags, int startId) {
		return super.onStartCommand(intent, flags, startId);
	}

	@Override
	public IBinder onBind(Intent intent) {
		return mBinder;
	}

	@Override
	public void onDestroy() {
		super.onDestroy();
		turnOffChatHead();
	}

	/*
	 * Connect to server with new thread
	 */
	public void connectServerXMPP() {
		new Thread(new Runnable() {

			@Override
			public void run() {
				ConnectionConfiguration connConfig = new ConnectionConfiguration(
						"smartsafe.vn", 5222);
				mConnection = new XMPPConnection(connConfig);

				while (!mConnection.isConnected()) {
					try {
						mConnection.connect();
						isConnected = true;
					} catch (XMPPException ex) {
						isConnected = false;
					}
					// reconnect each 3s if unsuccessful
					try {
						Thread.sleep(3000);
					} catch (InterruptedException e) {
					}
				}
			}
		}).start();
	}

	/**
	 * 
	 * @param acc
	 *            :input account
	 * @param pass
	 *            :input pass
	 * @return true if login successful, false otherwise
	 */
	public boolean login(String acc, String pass) {
		if (isConnected) {
			try {
				if (isLogin)
					logout();
				mConnection.login(acc, pass);
				isLogin = true;
				// Set the status to available
				Presence presence = new Presence(Presence.Type.available);
				mConnection.sendPacket(presence);
				return true;
			} catch (XMPPException e) {
				logout();
				isLogin = false;
				e.printStackTrace();
				return false;
			}
		}
		return false;
	}

	/**
	 * 
	 * @param acc
	 *            :input account
	 * @param pass
	 *            :input pass
	 * @return true if register successful, false otherwise
	 */
	public boolean register(String acc, String pass) {
		if (isConnected) {
			AccountManager accountManager = new AccountManager(mConnection);
			try {
				accountManager.createAccount(acc, pass);
				return true;
			} catch (XMPPException e) {
				e.printStackTrace();
			}
		}
		return false;
	}

	public void logout() {
		if (isConnected) {
			mConnection.disconnect();
			connectServerXMPP();
			isLogin = false;
		}
	}

	public String getUser() {
		return mConnection.getUser();
	}

	public boolean isConnect2Server() {
		return isConnected;
	}

	public boolean isLogin() {
		return isLogin;
	}

	// ====== Get information call taxi ======
	public void getNearCars(Context context, double lat, double lng,
			int numberCars, int numberKm, int carType) {
		GetNearCarTask task = new GetNearCarTask(context, lat, lng, numberCars,
				numberKm, carType);
		task.execute();
	}

	public void getCarInfo(Context context, String strTEID) {
		GetCarInfoTask task = new GetCarInfoTask(context, strTEID);
		task.execute();
	}

	public CarState getLastPosition() {
		if (strTEID != null) {
			HttpClient httpclient = new DefaultHttpClient();
			String url = "http://gps.smartsafe.vn/taxiws/Service1.svc/getLastPosition/"
					+ strTEID + "/0";
			HttpResponse response;
			try {
				response = httpclient.execute(new HttpGet(url));
				String data = StringUtils.readAllFromInputStream(response
						.getEntity().getContent());
				JSONArray arr = new JSONArray(data);
				JSONObject obj = arr.getJSONObject(0);
				return new CarState(obj.getDouble("dbLat"),
						obj.getDouble("dbLon"), obj.getInt("nFuel"),
						obj.getDouble("nSpeed"));
			} catch (IOException | JSONException e) {
				Log.e("topcbl", e.getMessage());
			}
		}
		return null;
	}

	// ======== Notification Taxi Coming ===========
	private WindowManager mWindowManager;
	private ImageView chatHead;
	private RelativeLayout mRoot;
	private WindowManager.LayoutParams mRootParams;
	private boolean isShow = true;
	private final float MIN_DISTANCE = 8;
	private final int ANIMATION_FRAME_RATE = 3;
	private final float DELTA = 3;
	private int chatHeadWidth;
	private int chatHeadHeight;

	private Handler mAnimationHandler = new Handler();
	private Timer mTimer;
	private TimerTask mTask;

	private LatLng mFirstPlace, mSecondPlace;
	private String strTEID;

	public void turnOnChatHead() {
		if (mRoot == null) {
			mWindowManager = (WindowManager) getSystemService(WINDOW_SERVICE);
			mRoot = (RelativeLayout) LayoutInflater.from(this).inflate(
					R.layout.chat_head, null);
			chatHead = (ImageView) mRoot.findViewById(R.id.image);
			Bitmap b = ((BitmapDrawable) chatHead.getBackground()).getBitmap();
			int chatHeadWidth = b.getWidth();
			int chatHeadHeight = b.getHeight();
			chatHead.setBackgroundResource(R.anim.animation_taxihead);
			((AnimationDrawable) chatHead.getBackground()).start();
			mRootParams = new WindowManager.LayoutParams(chatHeadWidth,
					chatHeadHeight, WindowManager.LayoutParams.TYPE_PHONE,
					WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE
							| WindowManager.LayoutParams.FLAG_LAYOUT_NO_LIMITS,
					PixelFormat.TRANSLUCENT);
			mRootParams.gravity = Gravity.TOP | Gravity.LEFT;
			mWindowManager.addView(mRoot, mRootParams);
			chatHead.setOnTouchListener(new MyTouchListener());
		}
	}

	public void turnOffChatHead() {
		if (mRoot != null) {
			mWindowManager.removeView(mRoot);
			mRoot = null;
			mFirstPlace = null;
			mSecondPlace = null;
			System.gc();
		}
	}

	private class MyTouchListener implements View.OnTouchListener {
		private float prevX;
		private float prevY;
		private float startX;
		private float startY;
		private final int mScreenWidth = getResources().getDisplayMetrics().widthPixels;
		private final int mScreenHeight = getResources().getDisplayMetrics().heightPixels;

		@Override
		public boolean onTouch(View v, MotionEvent event) {
			float x = event.getRawX();
			float y = event.getRawY();
			switch (event.getAction()) {
			case MotionEvent.ACTION_DOWN:
				prevX = startX = x;
				prevY = startY = y;
				return true;
			case MotionEvent.ACTION_MOVE:
				float dx = (x - prevX);
				float dy = (y - prevY);
				// action isn't move if delta < min
				if (Math.abs(dx) < MIN_DISTANCE || Math.abs(dy) < MIN_DISTANCE)
					return false;
				mRootParams.x += dx;
				mRootParams.y += dy;
				// don't move out of screen
				if (mRootParams.x < 0)
					mRootParams.x = 0;
				if (mRootParams.x + chatHeadWidth > mScreenWidth)
					mRootParams.x = mScreenWidth - chatHeadWidth;
				if (mRootParams.y < 0)
					mRootParams.y = 0;
				if (mRootParams.y + chatHeadHeight > mScreenHeight)
					mRootParams.y = mScreenHeight - chatHeadHeight;
				prevX = x;
				prevY = y;
				mWindowManager.updateViewLayout(mRoot, mRootParams);
				if (isShow) {
					sendBroadcast(new Intent("CloseWaitTaxiIntent"));
					isShow = false;
				}
				return true;
			case MotionEvent.ACTION_UP:
			case MotionEvent.ACTION_CANCEL:
				// identify event on click
				if (Math.abs(x - startX) < MIN_DISTANCE
						&& Math.abs(y - startY) < MIN_DISTANCE) {
					if (!isShow) {
						Intent intent = new Intent(getApplicationContext(),
								WaitTaxiActivity.class);
						intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
						startActivity(intent);
					} else {
						sendBroadcast(new Intent("CloseWaitTaxiIntent"));
					}
					isShow = !isShow;

				} else { // move back chat head to left edge
					mTimer = new Timer();
					mTask = new TimerTask() {
						TimerTask t = this;

						@Override
						public void run() {
							mAnimationHandler.post(new Runnable() {
								@Override
								public void run() {
									// Update coordinates of the tray
									mRootParams.x -= DELTA;
									// Cancel animation when touch left edge
									if (mRootParams.x < 0) {
										mRootParams.x = 0;
										t.cancel();
										mTimer.cancel();
									}
									mWindowManager.updateViewLayout(mRoot,
											mRootParams);
								}
							});
						}
					};
					mTimer.schedule(mTask, 0, ANIMATION_FRAME_RATE);
				}
				return true;
			}
			return false;
		}
	}

	public void setFirstPlace(LatLng p) {
		mFirstPlace = p;
	}

	public void setSecondPlace(LatLng p) {
		mSecondPlace = p;
	}

	public LatLng getFirstPlace() {
		return mFirstPlace;
	}

	public LatLng getSecondPlace() {
		return mSecondPlace;
	}

	public void setCurTEID(String id) {
		this.strTEID = id;
	}

	public String getCurTEID() {
		return strTEID;
	}

	public void setIsShow(boolean show) {
		isShow = show;
	}

	public boolean getIsShow() {
		return isShow;
	}

}
